// Copyright (c) 2023 Institute of Software, Chinese Academy of Sciences
// Ripple is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
//          http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.

package ripple.server.tcp.handler;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.socket.nio.NioSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ripple.common.DelayInjection;
import ripple.common.entity.*;
import ripple.common.tcp.Handler;
import ripple.common.tcp.Message;
import ripple.common.tcp.message.MQSyncRequest;
import ripple.common.tcp.message.MQSyncResponse;
import ripple.common.tcp.message.SyncRequest;
import ripple.common.tcp.message.SyncResponse;
import ripple.server.core.Node;

import java.net.InetSocketAddress;
import java.text.SimpleDateFormat;

public class MQSyncRequestHandler implements Handler {
    private static final Logger LOGGER = LoggerFactory.getLogger(MQSyncRequestHandler.class);

    private Node node;

    private Node getNode() {
        return node;
    }

    private void setNode(Node node) {
        this.node = node;
    }

    public MQSyncRequestHandler(Node node) {
        this.setNode(node);
    }

    @Override
    public Message handle(ChannelHandlerContext channelHandlerContext, Message message) {
        MQSyncRequest mqSyncRequest = (MQSyncRequest) message;
        InetSocketAddress localAddress = ((NioSocketChannel) channelHandlerContext.channel()).localAddress();
        InetSocketAddress remoteAddress = ((NioSocketChannel) channelHandlerContext.channel()).remoteAddress();

        DelayInjection.injectDelay(mqSyncRequest.getLastUpdateServerId(), this.getNode().getId());

        boolean result = false;
        

        AbstractMessage msg = null;
        if (mqSyncRequest.getOperationType().equals(Constants.MQ_MESSAGE)) {
            LOGGER.info("[MQSyncRequestHandler] [{}:{}<-->{}:{}] Receive SYNC request. UUID = {}, Message UUID = {}" +
                            ", Operation Type = {}, Topic = {}, Data String = {}, Last Update = {}" +
                            ", Last Update Server Id = {}."
                    , localAddress.getHostString(), localAddress.getPort(), remoteAddress.getHostString()
                    , remoteAddress.getPort(), mqSyncRequest.getUuid(), mqSyncRequest.getMessageUuid()
                    , mqSyncRequest.getOperationType(), mqSyncRequest.getTopic(), mqSyncRequest.getData().toString()
                    , SimpleDateFormat.getDateTimeInstance().format(mqSyncRequest.getLastUpdate())
                    , mqSyncRequest.getLastUpdateServerId());
            msg = new DataMessage(mqSyncRequest.getMessageUuid(), mqSyncRequest.getTopic(), mqSyncRequest.getData(), mqSyncRequest.getTowards()
                    , mqSyncRequest.getLastUpdate(), mqSyncRequest.getLastUpdateServerId());
//        } else if (MQSyncRequest.getOperationType().equals(Constants.MESSAGE_TYPE_DELETE)) {
//            LOGGER.info("[SyncRequestHandler] [{}:{}<-->{}:{}] Receive SYNC request. UUID = {}, Message UUID = {}" +
//                            ", Operation Type = {}, Application Name = {}, Key = {}, Last Update = {}" +
//                            ", Last Update Server Id = {}."
//                    , localAddress.getHostString(), localAddress.getPort(), remoteAddress.getHostString()
//                    , remoteAddress.getPort(), MQSyncRequest.getUuid(), MQSyncRequest.getMessageUuid()
//                    , MQSyncRequest.getOperationType(), MQSyncRequest.getApplicationName(), MQSyncRequest.getKey()
//                    , SimpleDateFormat.getDateTimeInstance().format(MQSyncRequest.getLastUpdate()), MQSyncRequest.getLastUpdateServerId());
//            msg = new DeleteMessage(MQSyncRequest.getMessageUuid(), MQSyncRequest.getApplicationName()
//                    , MQSyncRequest.getKey(), MQSyncRequest.getLastUpdate(), MQSyncRequest.getLastUpdateServerId());
//        } else if (MQSyncRequest.getOperationType().equals(Constants.MESSAGE_TYPE_INCREMENTAL_UPDATE)) {
//            LOGGER.info("[SyncRequestHandler] [{}:{}<-->{}:{}] Receive SYNC request. UUID = {}, Message UUID = {}" +
//                            ", Operation Type = {}, Application Name = {}, Key = {}, Base Message UUID = {}" +
//                            ", Atomic Operation = {}, Value = {}, Last Update = {}, Last Update Server Id = {}."
//                    , localAddress.getHostString(), localAddress.getPort(), remoteAddress.getHostString()
//                    , remoteAddress.getPort(), MQSyncRequest.getUuid(), MQSyncRequest.getMessageUuid()
//                    , MQSyncRequest.getOperationType(), MQSyncRequest.getApplicationName(), MQSyncRequest.getKey()
//                    , MQSyncRequest.getBaseMessageUuid(), MQSyncRequest.getAtomicOperation(), MQSyncRequest.getValue()
//                    , SimpleDateFormat.getDateTimeInstance().format(MQSyncRequest.getLastUpdate()), MQSyncRequest.getLastUpdateServerId());
//            msg = new IncrementalUpdateMessage(MQSyncRequest.getMessageUuid(), MQSyncRequest.getApplicationName()
//                    , MQSyncRequest.getKey(), MQSyncRequest.getBaseMessageUuid(), MQSyncRequest.getAtomicOperation()
//                    , MQSyncRequest.getValue(), MQSyncRequest.getLastUpdate(), MQSyncRequest.getLastUpdateServerId());
        }

        result = this.getNode().propagateMQMessage(msg);

        MQSyncResponse mqSyncResponse = new MQSyncResponse();
        mqSyncResponse.setUuid(mqSyncRequest.getUuid());
        mqSyncResponse.setSuccess(result);
        LOGGER.info("[SyncRequestHandler] [{}:{}<-->{}:{}] Send SYNC response. UUID = {}, Success = {}."
                , localAddress.getHostString(), localAddress.getPort(), remoteAddress.getHostString()
                , remoteAddress.getPort(), mqSyncResponse.getUuid(), mqSyncResponse.isSuccess());
        return mqSyncResponse;
    }
}